# 作者: Mark
# 2023年03月08日18时30分08秒
from socket import *
import select
import sys

def chat_server():
    #初始化一个套接字
    tcp_server_socket = socket(AF_INET,SOCK_STREAM)
    #重用对应地址和端口
    tcp_server_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    #绑定信息
    tcp_server_socket.bind(('',2000))
    #使用listen将套接字变为被动的，这样就可以接受别人的连接了
    tcp_server_socket.listen(10)


    #创建一个epoll对象
    epoll = select.epoll()
    #
    epoll.register(sys.stdin.fileno(),select.EPOLLIN)
    #
    epoll.register(tcp_server_socket.fileno(),select.EPOLLIN)

    client_dict = {}
    client_socket = None
    while True:
        # -1永久等待，轮询注册的事件集合，返回值为[(文件句柄，对应的事件)，(...),....]
        events = epoll.poll(-1)
        for event in events:
            if event[0]==tcp_server_socket.fileno():
                # 如果有新的客户端来链接服务器，那么就产生一个新的套接字专门为这个客户端服务
                client_socket, client_addr = tcp_server_socket.accept()
                print(f"{client_addr}连接上了！")
                epoll.register(client_socket.fileno(),select.EPOLLIN)  #代表一个client_socket加入监听
                #将这个新的客户端放入字典，键：client_socket文件描述符，值：client_socket
                client_dict[client_socket.fileno()] = client_socket




            else:    #代表client_socket接收缓冲区可读了
                recv_data = client_dict[event[0]].recv(1000)
                if recv_data:#如果有从缓冲区读到数据,就是对端还在发数据
                    print(f"recv:{recv_data.decode('utf8')}")
                    #发给其他客户端
                    for client in client_dict.items():
                        if client[0]!=client_socket.fileno():
                            client[1].send(recv_data)
                else:#如果没有从缓冲区读到数据，就是对端断开了
                    print('客户端断开了')
                    #解除对client_socket缓冲区的epoll注册
                    epoll.unregister(event[0])
                    #断开对此客户端的连接
                    client_dict[event[0]].close()
                    del client_dict[event[0]]
                    break

if __name__ == '__main__':
    chat_server()